/*
 *	tuple.h
 *  
 *  define tuple class here
 *  providing static named tuple access function
 *
 *	@author Wolfhead
 */

#pragma once

#ifndef _TUPLE_H_
#define _TUPLE_H_

#include "wfx.h"



// structure used in tuple class implementation
#include <map>
// exception base
#include <exception>

// tuple exception definition
struct exception_tuple_bad_referance : public std::exception{};




#define ATTRIBUTE(_tag, value)\
struct _tag\
	{\
	typedef value valueType;\
	static const char* getHash(){static const char* pHash = #_tag; return pHash ;}\
	typedef tuple_element<valueType> warpperType;\
	};\



// base class of all element stored in the tuple data
class tuple_element_base
{
public:
	virtual ~tuple_element_base(){};
};

// wrapper class of the real value we need to store
// subclass from tuple_element_base 
// NOTICE: We do nothing when we go out of scope
template<class T>
struct tuple_element : public tuple_element_base
{
	T member;
};



// class tuple
class tuple
{
public:
	/*
	 *	Destructor
	 *	We call Destructor on all the values stored in our tuple
	 *	When our tuple go out of scope
	 */
	virtual ~tuple()
	{
		
		for (std::map<const char*, tuple_element_base*>::iterator it = m_tuple.begin();
			it != m_tuple.end();
			++it)
		{
			delete it->second;
		}

	}

	// real data is saved in a std::map with T::getHash()
	// as its key
protected:

	std::map<const char*, tuple_element_base*> m_tuple;

public:

	// set 
	template<class T>
	void set(typename T::valueType value)
	{
		// create a wrapper class and put real value in the wrapper 

		//BUGBUG
		//when do we free the space
		typename T::warpperType * pWarpper = new T::warpperType();
		pWarpper->member = value;
		
		// store the wrapper 
		m_tuple[T::getHash()] = pWarpper; 
	}

	template<class T>
	typename T::valueType get()
	{
		if ( m_tuple.find(T::getHash()) == m_tuple.end() )
		{
			throw exception_tuple_bad_referance();
		}
		else
		{
			return ((typename T::warpperType *)(m_tuple[T::getHash()]))->member;
		}
	}
};





#endif //_TUPLE_H_